package com.qs.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qs.constant.CacheConstant;
import com.qs.exception.ServiceException;
import com.qs.mapper.CartMapper;
import com.qs.mapper.GoodsMapper;
import com.qs.mapper.StoreMapper;
import com.qs.model.dto.CartDto;
import com.qs.model.dto.OrderDto;
import com.qs.model.entity.*;
import com.qs.model.enums.PayInfoEnum;
import com.qs.model.vo.OrderInfoVo;
import com.qs.response.ResponseEnum;
import com.qs.service.IAsyncService;
import com.qs.service.ICartService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 购物车表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-03-29
 */
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

    private final GoodsMapper goodsMapper;
    private final StoreMapper storeMapper;
    private final IAsyncService asyncService;
    private final RedisTemplate redisTemplate;

    @Override
    public void addCart(Cart cart) {
        Goods goods = goodsMapper.selectById(cart.getGoodsId());
        //此处可以优化，完全可以在用户多添加一个商品时查询商品库存是否够
        if(goods.getNumber() < cart.getNumber()) {
            throw new ServiceException(ResponseEnum.GOODS_NUM_INSUFFICIENT);
        }
        QueryWrapper<Cart> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",cart.getUserId());
        wrapper.eq("goods_id",cart.getGoodsId());
        Cart selectOne = baseMapper.selectOne(wrapper);
        if(null == selectOne){
            //说明是第一次添加
            baseMapper.insert(cart);
        }else{
            selectOne.setNumber(cart.getNumber());
            baseMapper.updateById(selectOne);
        }
    }

    @Override
    public List<CartDto> queryCartData(Integer userId) {
        QueryWrapper<Cart> wrapper = new QueryWrapper<Cart>().eq("user_id", userId);
        wrapper.orderByDesc("create_time");
        List<Cart> carts = baseMapper.selectList(wrapper);
        if(!CollectionUtils.isEmpty(carts)) {
            List<CartDto> list = new ArrayList<CartDto>();
            carts.stream().forEach(cart -> {
                Goods goods = goodsMapper.selectById(cart.getGoodsId());
                Store store = storeMapper.selectById(goods.getStoreId());
                CartDto cartDto = new CartDto();
                cartDto.setId(cart.getId());
                cartDto.setGoodsId(goods.getId());
                cartDto.setStoreId(store.getId());
                cartDto.setGoodsName(goods.getName());
                cartDto.setPrice(goods.getPrice());
                cartDto.setImage(goods.getImage());
                cartDto.setNumber(cart.getNumber());
                cartDto.setTotalPrice(cart.getNumber() * goods.getPrice());
                list.add(cartDto);
            });
            return list;
        }
        return null;
    }

    @Override
    public void updateCart(Cart cart) {
        Goods goods = goodsMapper.selectById(cart.getGoodsId());
        //此处可以优化，完全可以在用户多添加一个商品时查询商品库存是否够
        if(goods.getNumber() < cart.getNumber()) {
            throw new ServiceException(ResponseEnum.GOODS_NUM_INSUFFICIENT);
        }

        QueryWrapper<Cart> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",cart.getUserId());
        wrapper.eq("goods_id",cart.getGoodsId());
        Cart selectOne = baseMapper.selectOne(wrapper);
        if(null != selectOne){
            selectOne.setNumber(cart.getNumber());
            baseMapper.updateById(selectOne);
        }
    }

    @Override
    public OrderInfoVo queryOrderDetail(OrderDto orderDto) {
        //生成一个唯一的订单id
        String orderId = IdUtil.getSnowflakeNextIdStr();
        //缓存订单id
        redisTemplate.opsForValue().set(CacheConstant.ORDER_ID_CODE + orderId, orderId,CacheConstant.ORDER_ID_CODE_EXPIRE, TimeUnit.MINUTES);
        //查询店铺数据
        Store store = storeMapper.selectById(orderDto.getStoreId());
        //查询商品数据
        Goods goods = goodsMapper.selectById(orderDto.getGoodsId());
        //查询购物车数据
        Cart cart = baseMapper.selectById(orderDto.getCartId());
        //封装订单详细数据
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        orderInfoVo.setOrderId(orderId);
        orderInfoVo.setStoreName(store.getHomeName());
        orderInfoVo.setGoodsImage(goods.getImage());
        orderInfoVo.setGoodsName(goods.getName());
        orderInfoVo.setSale(goods.getSale());
        orderInfoVo.setPrice(goods.getPrice());
        orderInfoVo.setNumber(cart.getNumber());
        orderInfoVo.setTotalPrice(goods.getPrice() *  cart.getNumber());

        //TODO: 验证和锁定库存,这里默认不进行，后续要修改

        //以下就是异步去保存订单的相关数据，最后返回订单Id
        //分别补充qs_order_info；qs_order_item；qs_pay_info；qs_user_goods_log数据
        //qs_order_info
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderId(orderId);
        orderInfo.setAddressId(orderDto.getAddressId());
        orderInfo.setUserId(orderDto.getUserId());
        orderInfo.setTotalPrice(goods.getPrice() *  cart.getNumber());
        asyncService.saveOrderInfo(orderInfo);

        //qs_order_item
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(orderId);
        orderItem.setGoodsId(orderDto.getGoodsId());
        orderItem.setNumber(cart.getNumber());
        orderItem.setSubTotalPrice(goods.getPrice() *  cart.getNumber());
        asyncService.saveOrderItem(orderItem);

        //qs_pay_info
        PayInfo payInfo = new PayInfo();
        payInfo.setUserId(orderDto.getUserId());
        payInfo.setOrderId(orderId);
        //TODO: 默认使用支付宝支付类型，后续可修改
        payInfo.setType("alipay");
        payInfo.setStatus(PayInfoEnum.WAIT_PAY);
        asyncService.savePayInfo(payInfo);

        //将购物车中的数据删除
        asyncService.deleteCart(orderDto.getCartId());
        return orderInfoVo;
    }
}
